package org.budo.phone.freeswitch.util;

import java.util.Map;

import org.budo.phone.api.BudoPhoneEvent;
import org.budo.phone.api.BudoPhoneEvent.CallState;
import org.budo.phone.api.BudoPhoneEvent.Direction;
import org.budo.phone.api.BudoPhoneEvent.Type;
import org.budo.phone.freeswitch.FreeswitchPhoneEvent;
import org.budo.support.lang.util.StringUtil;
import org.freeswitch.esl.client.transport.event.EslEvent;

import com.alibaba.fastjson.JSON;

import lombok.extern.slf4j.Slf4j;

/**
 * @author lmw
 */
@Slf4j
public class PhoneEventUtil {

    private static final String CHANNEL_CALL_STATE_KEY="Channel-Call-State";
    public static String getCallUuid(EslEvent eslEvent) {
        String eventName = eslEvent.getEventName();

        Map<String, String> eventHeaders = eslEvent.getEventHeaders();
        String userData = eventHeaders.get("variable_sip_rh_P-Call-UserData");
        String channelCallUuid = eventHeaders.get("Caller-Unique-ID");
        String variableUuid = eventHeaders.get("variable_uuid");

        // 没有 UserData，用 channelCallUuid
        if (null == userData || userData.isEmpty() || "null".equalsIgnoreCase(userData.trim())) {
            return uuidToCallId(channelCallUuid);
        }

        // 用 userData
        if (userData.startsWith("servercallid=")) {
            String id = userData.substring(13);
            //成都电信的servercallid是这样子的servercallid=2002241658061040000100490084c830;tel=02863847636;
            if(id.contains("tel")){
                return uuidToCallId(channelCallUuid);
            }
            return id;
        }

        // 不以servercallid=开头的userData
        log.error("#32 channelCallUuid=" + channelCallUuid + ", userData=" + userData + ", variableUuid=" + variableUuid + ", eventName=" + eventName);
        return uuidToCallId(variableUuid);
    }

    public static FreeswitchPhoneEvent phoneEvent(EslEvent eslEvent, Type eventType) {
        Map<String, String> eventHeaders = eslEvent.getEventHeaders();

        String callUuid = getCallUuid(eslEvent);
        String sipUser = getSipUser(eventHeaders);

        if (StringUtil.isNullOrEmpty(sipUser)) {
            log.warn("#52 phoneEvent, sipUser=" + sipUser + ", eventHeaders=" + eventHeaders);
        }

        // 一通电话会收到两个接通，两个挂断时间；其中一个 variable_effective_caller_id_number 为空，且
        FreeswitchPhoneEvent phoneEvent = new FreeswitchPhoneEvent();
        phoneEvent.setEventName(eslEvent.getEventName());
        phoneEvent.setType(eventType);

        phoneEvent.setCallId(callUuid);

        phoneEvent.setSipUser(sipUser);

        // Caller-Destination-Number
        // variable_sip_to_user
        // variable_sip_req_user
        String destinationNumber = eventHeaders.get("Caller-Destination-Number");

        phoneEvent.setToNumber(destinationNumber);

        String fromNumber = eventHeaders.get("variable_sip_from_user");
        if(StringUtil.isEmpty(fromNumber)
                || fromNumber.equals(destinationNumber)){
            fromNumber=eventHeaders.get("Caller-Orig-Caller-ID-Number");
        }
        phoneEvent.setFromNumber(fromNumber);

        Direction direction = PhoneEventUtil.direction(eventHeaders);
        phoneEvent.setDirection(direction);


        CallState callState = CallState.getCallStateByName(eventHeaders.get(CHANNEL_CALL_STATE_KEY));
        phoneEvent.setCallState(callState);

        phoneEvent.setHeaders(eventHeaders);

        String aLegCallId= PhoneEventUtil.uuidToCallId(eventHeaders.get("variable_cc_member_session_uuid"));
        phoneEvent.setALegCallId(aLegCallId);

        return phoneEvent;
    }

    // "variable_sip_to_user": "90116",
    // "Caller-Callee-ID-Number": "90116",
    // "variable_original_destination_number": "90116",
    // "variable_effective_caller_id_number": "90116",
    // "variable_dialed_user": "90116",
    // "variable_accountcode": "90116",
    // "variable_sip_contact_user": "90116",
    // "Caller-Destination-Number": "90116",
    // "variable_cc_agent": "90116",
    // "Caller-Callee-ID-Number": "90116",
    public static String getSipUser(Map<String, String> eventHeaders) {
        String callerUsername = eventHeaders.get("Caller-Username");
        if (StringUtil.isNotNullOrEmpty(callerUsername)) {
            return callerUsername;
        }

        String variable_accountcode = eventHeaders.get("variable_accountcode");
        if (StringUtil.isNotNullOrEmpty(variable_accountcode)) {
            return variable_accountcode;
        }

        String callerCalleeIdNumber=eventHeaders.get("Caller-Callee-ID-Number");
        if (StringUtil.isNotNullOrEmpty(callerCalleeIdNumber)) {
            return callerCalleeIdNumber;
        }

        String otherLegChannelName = eventHeaders.get("Other-Leg-Channel-Name");
        if (StringUtil.isNotNullOrEmpty(otherLegChannelName) //
                && otherLegChannelName.startsWith("sofia/internal/") //
                && otherLegChannelName.contains("@")) {
            int a = otherLegChannelName.indexOf('@');
            String sipUser = otherLegChannelName.substring(15, a);
            return sipUser;
        }

        // 群呼时也可能取到被叫号
        String variable_sip_to_user = eventHeaders.get("variable_sip_to_user");
        if (StringUtil.isNotNullOrEmpty(variable_sip_to_user)) {
            return variable_sip_to_user;
        }

        log.warn("#99 getSipUser return null, eventHeaders=" + JSON.toJSONString(eventHeaders));
        return null;
    }

    public static BudoPhoneEvent.Direction direction(Map<String, String> eventHeaders) {
        String eventName = eventHeaders.get("Event-Name");
        if ("RE_SCHEDULE".equals(eventName) ) {
            return null;
        }

        String variable_direction = readDirectionFromHeader(eventHeaders);
        if (null == variable_direction || variable_direction.trim().isEmpty() || "null".equalsIgnoreCase(variable_direction.trim())) {
            log.error("#61 variable_direction=" + variable_direction + ", eventHeaders=" + JSON.toJSONString(eventHeaders));
            return null;
        }

        if ("inbound".equalsIgnoreCase(variable_direction)) {
            return BudoPhoneEvent.Direction.Inbound;
        }

        if ("outbound".equalsIgnoreCase(variable_direction)) {
            return BudoPhoneEvent.Direction.Outbound;
        }

        throw new RuntimeException("#251 variable_direction=" + variable_direction + ", eventHeaders=" + JSON.toJSONString(eventHeaders));
    }

//  {   
//      "Presence-Call-Direction": "inbound",
//      "Caller-Direction": "inbound",
//      "Caller-Logical-Direction": "inbound",
//      "Call-Direction": "inbound",
//  }
    public static String readDirectionFromHeader(Map<String, String> eventHeaders) {

        String direction = eventHeaders.get("variable_direction");
        if (null != direction && !direction.trim().isEmpty() && !"null".equalsIgnoreCase(direction.trim())) {
            return direction;
        }

        direction = eventHeaders.get("Call-Direction");
        if (null != direction && !direction.trim().isEmpty() && !"null".equalsIgnoreCase(direction.trim())) {
            return direction;
        }

        log.error("#93 readDirectionFromHeader, eventHeaders=" + JSON.toJSONString(eventHeaders));
        return null;
    }

    public static Type eventType(EslEvent event) {
        String eventName = event.getEventName();

        if ("CHANNEL_CREATE".equalsIgnoreCase(eventName)) {
            return Type.ChannelCreate;
        }
        if ("CHANNEL_PROGRESS".equalsIgnoreCase(eventName)) {
            return Type.ReachService;
        }

        if ("CHANNEL_ANSWER".equalsIgnoreCase(eventName)) {
            return Type.CallEstablish;
        }

        if ("CHANNEL_HANGUP_COMPLETE".equalsIgnoreCase(eventName)) {
            return Type.HangupComplete;
        }

        // 需要细调
        if (isStopService(event)) {
            return Type.StopService;
        }

        // CHANNEL_DESTROY 有可能是 StopService
        if ("CHANNEL_DESTROY".equalsIgnoreCase(eventName)) {
            return Type.Hangup;
        }

        if ("CHANNEL_CALLSTATE".equalsIgnoreCase(eventName)) {
            return Type.AgentState;
        }

        if ("RECORD_STOP".equalsIgnoreCase(eventName)) {
            return Type.RecordStop;
        }
        if (isSkipEvent(eventName)) {
            return null;
        }

        log.debug("#317 eventName=" + eventName);
        return null;
    }

    public static boolean isStopService(EslEvent event) {
        String eventName = event.getEventName();

        // 这两种事件对应 StopService
        if (!"CHANNEL_HANGUP".equalsIgnoreCase(eventName) //
                && !"CHANNEL_DESTROY".equalsIgnoreCase(eventName)) {
            return false;
        }

        Map<String, String> eventHeaders = event.getEventHeaders();
        String variableExportVars = eventHeaders.get("variable_export_vars"); // sip_rh_P-Call-UserData
        if (StringUtil.equals("sip_rh_P-Call-UserData", variableExportVars)) {
            log.debug("#160 out call no stopservice, variable_export_vars={}, event={}", variableExportVars, event);
            return false; // 外呼
        }

        String curlResponseData = eventHeaders.get("variable_curl_response_data"); // {absolute_codec_string=PCMA,origination_caller_id_number=1002}sofia/gateway/gw77/13648382702
        if (!StringUtil.isEmpty(curlResponseData) && curlResponseData.contains("{absolute_codec_string=") //
                && curlResponseData.contains(",origination_caller_id_number=")) {
            log.error("#167 variable_curl_response_data=" + curlResponseData + " event=" + event);
            return false; // 外呼
        }

        return true;
    }

    public static Boolean isSkipEvent(String eventName) {
        return "HEARTBEAT".equalsIgnoreCase(eventName) //
                || "CUSTOM".equalsIgnoreCase(eventName) //
                || "CHANNEL_STATE".equalsIgnoreCase(eventName) //
                || "PRESENCE_IN".equalsIgnoreCase(eventName) //
                || "CHANNEL_ORIGINATE".equalsIgnoreCase(eventName) //
                || "CHANNEL_OUTGOING".equalsIgnoreCase(eventName) //
                || "MODULE_UNLOAD".equalsIgnoreCase(eventName) //
                || "API".equalsIgnoreCase(eventName) //
                || "CHANNEL_EXECUTE".equalsIgnoreCase(eventName) //
                || "CHANNEL_EXECUTE_COMPLETE".equalsIgnoreCase(eventName) //
                || "CHANNEL_PROGRESS_MEDIA".equalsIgnoreCase(eventName) //
                || "CHANNEL_BRIDGE".equalsIgnoreCase(eventName) //
                || "PLAYBACK_START".equalsIgnoreCase(eventName) //
                || "PLAYBACK_STOP".equalsIgnoreCase(eventName) //
                || "RE_SCHEDULE".equalsIgnoreCase(eventName) //
                || "MESSAGE_QUERY".equalsIgnoreCase(eventName) //
                || "MESSAGE_WAITING".equalsIgnoreCase(eventName) //
                || "MEDIA_BUG_START".equalsIgnoreCase(eventName) //
                || "MEDIA_BUG_STOP".equalsIgnoreCase(eventName) //
                || "RECORD_START".equalsIgnoreCase(eventName) //
                || "CALL_UPDATE".equalsIgnoreCase(eventName) //
                || "CHANNEL_UNBRIDGE".equalsIgnoreCase(eventName) //
                || "RECORD_STOP".equalsIgnoreCase(eventName) //
                || "RECV_INFO".equalsIgnoreCase(eventName) //
                || "RECV_RTCP_MESSAGE".equalsIgnoreCase(eventName) //
                || "CHANNEL_CREATE".equalsIgnoreCase(eventName) //
                || "CHANNEL_HANGUP".equalsIgnoreCase(eventName) //
                || "CHANNEL_CALLSTATE".equals(eventName) //
                || "CODEC".equalsIgnoreCase(eventName);
    }

    public static String uuidToCallId(String uuid) {
        if (null == uuid || uuid.length() != 36) {
            return uuid;
        }

        return uuid.replace("-", "");
    }

    public static String callIdToUuid(String callId) {
        if (null == callId || callId.length() != 32) {
            return callId;
        }

        return callId.substring(0, 8) //
                + "-" + callId.substring(8, 12) //
                + "-" + callId.substring(12, 16) //
                + "-" + callId.substring(16, 20) //
                + "-" + callId.substring(20);
    }
}